using System;
using System.Collections;

namespace csammisrun.OscarLib.Utility
{
	/// <summary>
	/// Provides static methods for processing messages in SNAC family 0x000F -- Directory search service
	/// </summary>
	internal static class SNAC0F
	{
    /// <summary>
		/// Performs a directory search by email address -- SNAC(0F,02)
		/// </summary>
		/// <param name="sess">A <see cref="Session"/> object</param>
		/// <param name="email">The email address to search for</param>
		public static void SearchByEmail(Session sess, string email)
		{
			SNACHeader sh = new SNACHeader();
			sh.FamilyServiceID = (ushort)SNACFamily.DirectoryUserSearch;
			sh.FamilySubtypeID = (ushort)DirectorySearch.SearchUserRequest;
			sh.Flags = 0x0000;
			sh.RequestID = sess.GetNextRequestID();

			TLV[] tlvs = new TLV[3];
      tlvs[0] = TLVMarshal.MakeTLV(0x001C, Marshal.StringToByteArray("us-ascii", Marshal.ASCII));
			tlvs[1] = TLVMarshal.MakeTLV(0x000A, Marshal.UShortToByteArray(0x0001));
      tlvs[2] = TLVMarshal.MakeTLV(0x0005, Marshal.StringToByteArray(email, Marshal.ASCII));

			DataPacket dp = Marshal.BuildDataPacket(sess, sh, TLVMarshal.TLVsToByteArray(tlvs));
			SNACFunctions.BuildFLAP(dp);
		}

		/// <summary>
		/// Performs a directory search by personal information -- SNAC(0F,02)
		/// </summary>
		/// <param name="sess">A <see cref="Session"/> object</param>
		/// <param name="items">The number of non-null search terms</param>
		/// <param name="firstname">A first name</param>
		/// <param name="middlename">A middle name</param>
		/// <param name="lastname">A last name</param>
		/// <param name="maidenname">A maiden name</param>
		/// <param name="nickname">A nickname</param>
		/// <param name="city">A city</param>
		/// <param name="state">A state</param>
		/// <param name="country">A country (two letter code)</param>
		/// <param name="zip">A ZIP code</param>
		/// <param name="address">An address</param>
		/// <remarks>
		/// <para>If a search term is to be ignored, it must be set to <c>null</c>.</para>
		/// <para>There must be at least one non-null search term.</para></remarks>
		public static void SearchByInfo(
			Session sess, int items,
			string firstname, string middlename, string lastname, string maidenname, string nickname,
			string city, string state, string country, string zip, string address)
		{
			SNACHeader sh = new SNACHeader();
			sh.FamilyServiceID = (ushort)SNACFamily.DirectoryUserSearch;
			sh.FamilySubtypeID = (ushort)DirectorySearch.SearchUserRequest;
			sh.Flags = 0x0000;
			sh.RequestID = sess.GetNextRequestID();

			TLV[] tlvs = new TLV[2 + items];
      tlvs[0] = TLVMarshal.MakeTLV(0x001C, Marshal.StringToByteArray("us-ascii", Marshal.ASCII));
			tlvs[1] = TLVMarshal.MakeTLV(0x000A, Marshal.UShortToByteArray(0x0000));

			int index = 2;
			if(firstname != null)
        tlvs[index++] = TLVMarshal.MakeTLV(0x0001, Marshal.StringToByteArray(firstname, Marshal.ASCII));
			if(middlename != null)
        tlvs[index++] = TLVMarshal.MakeTLV(0x0002, Marshal.StringToByteArray(middlename, Marshal.ASCII));
			if(lastname != null)
        tlvs[index++] = TLVMarshal.MakeTLV(0x0003, Marshal.StringToByteArray(lastname, Marshal.ASCII));
			if(maidenname != null)
        tlvs[index++] = TLVMarshal.MakeTLV(0x0004, Marshal.StringToByteArray(maidenname, Marshal.ASCII));
			if(country != null)
        tlvs[index++] = TLVMarshal.MakeTLV(0x0006, Marshal.StringToByteArray(country, Marshal.ASCII));
			if(state != null)
        tlvs[index++] = TLVMarshal.MakeTLV(0x0007, Marshal.StringToByteArray(state, Marshal.ASCII));
			if(city != null)
        tlvs[index++] = TLVMarshal.MakeTLV(0x0008, Marshal.StringToByteArray(city, Marshal.ASCII));
			if(nickname != null)
        tlvs[index++] = TLVMarshal.MakeTLV(0x000C, Marshal.StringToByteArray(nickname, Marshal.ASCII));
			if(zip != null)
        tlvs[index++] = TLVMarshal.MakeTLV(0x000D, Marshal.StringToByteArray(zip, Marshal.ASCII));
			if(address != null)
        tlvs[index++] = TLVMarshal.MakeTLV(0x0021, Marshal.StringToByteArray(address, Marshal.ASCII));

			DataPacket dp = Marshal.BuildDataPacket(sess, sh, TLVMarshal.TLVsToByteArray(tlvs));
			SNACFunctions.BuildFLAP(dp);
		}

		/// <summary>
		/// Performs a directory search by interest -- SNAC(0F,02)
		/// </summary>
		/// <param name="sess">A <see cref="Session"/> object</param>
		/// <param name="interest">The interest to search for</param>
		public static void SearchByInterest(Session sess, string interest)
		{
			SNACHeader sh = new SNACHeader();
			sh.FamilyServiceID = (ushort)SNACFamily.DirectoryUserSearch;
			sh.FamilySubtypeID = (ushort)DirectorySearch.SearchUserRequest;
			sh.Flags = 0x0000;
			sh.RequestID = sess.GetNextRequestID();

			TLV[] tlvs = new TLV[3];
      tlvs[0] = TLVMarshal.MakeTLV(0x001C, Marshal.StringToByteArray("us-ascii", Marshal.ASCII));
			tlvs[1] = TLVMarshal.MakeTLV(0x000A, Marshal.UShortToByteArray(0x0001));
      tlvs[2] = TLVMarshal.MakeTLV(0x0001, Marshal.StringToByteArray(interest, Marshal.ASCII));

			DataPacket dp = Marshal.BuildDataPacket(sess, sh, TLVMarshal.TLVsToByteArray(tlvs));
			SNACFunctions.BuildFLAP(dp);
		}

		/// <summary>
		/// Processes the parameter information sent by the server -- SNAC(0F,03)
		/// </summary>
		/// <param name="dp">A <see cref="DataPacket"/> object with a buffer containing SNAC(0F,03)</param>
		public static void ProcessSearchResults(DataPacket dp)
		{
			byte[] SNACData = dp.Data;

			int index = 0;
			Marshal.ByteArrayToUshort(SNACData, ref index);
			ushort tmp = Marshal.ByteArrayToUshort(SNACData, ref index);
			index += tmp;

			ushort numresults = Marshal.ByteArrayToUshort(SNACData, ref index);
			DirectoryEntry[] results = new DirectoryEntry[numresults];
			ushort key, keylength;
			for(int i = 0; i < numresults; i++)
			{
				results[i] = new DirectoryEntry();
				key = Marshal.ByteArrayToUshort(SNACData, ref index);
				keylength = Marshal.ByteArrayToUshort(SNACData, ref index);
				switch(key)
				{
					case 0x0001:
            results[i].FirstName = Marshal.ByteArrayToString(SNACData, ref index, keylength, Marshal.ASCII);
						break;
					case 0x0002:
            results[i].LastName = Marshal.ByteArrayToString(SNACData, ref index, keylength, Marshal.ASCII);
						break;
					case 0x0003:
            results[i].MiddleName = Marshal.ByteArrayToString(SNACData, ref index, keylength, Marshal.ASCII);
						break;
					case 0x0004:
            results[i].MaidenName = Marshal.ByteArrayToString(SNACData, ref index, keylength, Marshal.ASCII);
						break;
					case 0x0005:
            results[i].Email = Marshal.ByteArrayToString(SNACData, ref index, keylength, Marshal.ASCII);
						break;
					case 0x0006:
            results[i].Country = Marshal.ByteArrayToString(SNACData, ref index, keylength, Marshal.ASCII);
						break;
					case 0x0007:
            results[i].State = Marshal.ByteArrayToString(SNACData, ref index, keylength, Marshal.ASCII);
						break;
					case 0x0008:
            results[i].City = Marshal.ByteArrayToString(SNACData, ref index, keylength, Marshal.ASCII);
						break;
					case 0x0009:
            results[i].ScreenName = Marshal.ByteArrayToString(SNACData, ref index, keylength, Marshal.ASCII);
						break;
					case 0x000B:
            results[i].Interest = Marshal.ByteArrayToString(SNACData, ref index, keylength, Marshal.ASCII);
						break;
					case 0x000C:
            results[i].NickName = Marshal.ByteArrayToString(SNACData, ref index, keylength, Marshal.ASCII);
						break;
					case 0x000D:
            results[i].ZIPCode = Marshal.ByteArrayToString(SNACData, ref index, keylength, Marshal.ASCII);
						break;
					case 0x001C:
            results[i].Region = Marshal.ByteArrayToString(SNACData, ref index, keylength, Marshal.ASCII);
						break;
					case 0x0021:
            results[i].Address = Marshal.ByteArrayToString(SNACData, ref index, keylength, Marshal.ASCII);
						break;
					default:
						index += keylength;
						break;
				}
			}

			dp.ParentSession.OnSearchResults(results);
		}

		/// <summary>
		/// Requests a list of known interests -- SNAC(0F,04)
		/// </summary>
		/// <param name="sess">A <see cref="Session"/> object</param>
		public static void RequestInterestList(Session sess)
		{
			SNACHeader sh = new SNACHeader();
			sh.FamilyServiceID = (ushort)SNACFamily.DirectoryUserSearch;
			sh.FamilySubtypeID = (ushort)DirectorySearch.InterestsListRequest;
			sh.Flags = 0x0000;
			sh.RequestID = sess.GetNextRequestID();

			DataPacket dp = Marshal.BuildDataPacket(sess, sh, null);
			SNACFunctions.BuildFLAP(dp);
		}

		/// <summary>
		/// Processes a list of known interests from the server -- SNAC(0F,05)
		/// </summary>
		/// <param name="dp">A <see cref="DataPacket"/> object with a buffer containing SNAC(0F,05)</param>
		/// <remarks>
		/// libfaim doesn't implement the interest list fetching, so this one's thanks to Mark Doliner's
		/// (thekingant@users.sourceforge.net) documentation.
		/// </remarks>
		public static void ProcessInterestList(DataPacket dp)
		{
			byte[] SNACData = dp.Data;

			int index = 2;	// First two bytes: 0x0001
			ushort num_items = Marshal.ByteArrayToUshort(SNACData, ref index);
			InterestItem[] interests = new InterestItem[num_items];
			for(int i = 0; i < num_items; i++)
			{
				interests[i] = Marshal.GetInterestItem(SNACData, ref index);
			}

			dp.ParentSession.OnInterestsReceived(interests);
		}
	}
}
